#ifndef __DiffMuscle_h__
#define __DiffMuscle_h__

#include <OpenSim/Actuators/osimActuatorsDLL.h>
#include <OpenSim/Simulation/Model/ActivationFiberLengthMuscle.h>
#include "osimPluginDLL.h"


#ifdef SWIG

	#ifdef OSIMACTUATORS_API

		#undef OSIMACTUATORS_API

		#define OSIMACTUATORS_API

	#endif

#endif



namespace OpenSim {

class OSIMPLUGIN_API DiffMuscle :
	public ActivationFiberLengthMuscle
{
//=============================================================================
// DATA
//=============================================================================
	protected:
	/** Activation time constant */  
	PropertyDbl _activationTimeConstantProp[2];
	double &_activationTimeConstantFastFiber;
	double &_activationTimeConstantSlowFiber;

	/** Deactivation time constant */
	PropertyDbl _deactivationTimeConstantProp[2];
	double &_deactivationTimeConstantFastFiber;
	double &_deactivationTimeConstantSlowFiber;


	/** Max contraction velocity full activation in fiber lengths per second */
	PropertyDbl _vmaxProp[2];
	double &_vmaxFastFiber;
	double &_vmaxSlowFiber;

	/** Max contraction velocity at low activation */
	PropertyDbl _vmax0Prop[2];
	double &_vmax0FastFiber;
	double &_vmax0SlowFiber;

	/** Tendon strain due to maximum isometric muscle force */
	PropertyDbl _fmaxTendonStrainProp;
	double &_fmaxTendonStrain;

	/** Passive muscle strain due to maximum isometric muscle force */
	PropertyDbl _fmaxMuscleStrainProp;
	double &_fmaxMuscleStrain;

	/** Shape factor for Gaussian active muscle force-length relationship */
	PropertyDbl _kShapeActiveProp[2];
	double &_kShapeActiveFastFiber;
	double &_kShapeActiveSlowFiber;

	/** Exponential shape factor for passive force-length relationship */
	PropertyDbl _kShapePassiveProp;
	double &_kShapePassive;
	
	/** Passive damping included in the force-velocity relationship */
	PropertyDbl _dampingProp;
	double &_damping;

	/** Force-velocity shape factor */
	PropertyDbl _afProp[2];
	double &_afFastFiber;
	double &_afSlowFiber;

	/** Maximum normalized lengthening force */
	PropertyDbl _flenProp;
	double &_flen;

	

protected:
	static const int STATE_ACTIVATION_FAST_FIBER;
	static const int STATE_ACTIVATION_SLOW_FIBER;
	
//=============================================================================
// METHODS
//=============================================================================
	//--------------------------------------------------------------------------
	// CONSTRUCTION
	//--------------------------------------------------------------------------
public:
	DiffMuscle();
	DiffMuscle(const std::string &aName,double aMaxIsometricForce,double aOptimalFiberLength,double aTendonSlackLength,double aPennationAngle);
	DiffMuscle(const DiffMuscle &aMuscle);
	virtual ~DiffMuscle();
	virtual Object* copy() const;

#ifndef SWIG
	DiffMuscle& operator=(const DiffMuscle &aMuscle);
#endif
	void copyData(const DiffMuscle &aMuscle);

#ifndef SWIG

#endif

	//--------------------------------------------------------------------------
	// GET
	//--------------------------------------------------------------------------
	// Properties
	virtual double getActivationTimeConstantFastFiberFastFiber() const { return _activationTimeConstantFastFiber; }
	virtual double getActivationTimeConstantFastFiberSlowFiber() const { return _activationTimeConstantSlowFiber; }
	virtual double getDeactivationTimeConstantFastFiber() const { return _deactivationTimeConstantFastFiber; }
	virtual double getDeactivationTimeConstantSlowFiber() const { return _deactivationTimeConstantSlowFiber; }
	virtual double getVmaxFastFiber() const { return _vmaxFastFiber; }
	virtual double getVmaxSlowFiber() const { return _vmaxSlowFiber; }
	virtual double getVmax0FastFiber() const { return _vmax0FastFiber; }
	virtual double getVmax0SlowFiber() const { return _vmax0SlowFiber; }
	virtual double getFmaxTendonStrain() const { return _fmaxTendonStrain; }
	virtual double getFmaxMuscleStrain() const { return _fmaxMuscleStrain; }
	virtual double getKshapeActiveFastFiber() const { return _kShapeActiveFastFiber; }
	virtual double getKshapeActiveSlowFiber() const { return _kShapeActiveSlowFiber; }
	virtual double getKshapePassive() const { return _kShapePassive; }
	virtual double getDamping() const { return _damping; }
	virtual double getAfFastFiber() const { return _afFastFiber; }
	virtual double getAfSlowFiber() const { return _afSlowFiber; }
	virtual double getFlen() const { return _flen; }
	virtual bool setActivationTimeConstant(double aActivationTimeConstant[]);
	virtual bool setDeactivationTimeConstant(double aDeactivationTimeConstant[]);
	virtual bool setVmax(double aVmax[]);
	virtual bool setVmax0(double aVmax0[]);
	virtual bool setFmaxTendonStrain(double aFmaxTendonStrain);
	virtual bool setFmaxMuscleStrain(double aFmaxMuscleStrain);
	virtual bool setKshapeActive(double aKShapeActive[]);
	virtual bool setKshapePassive(double aKshapePassive);
	virtual bool setDamping(double aDamping);
	virtual bool setAf(double aAf[]);
	virtual bool setFlen(double aFlen);

	// Computed quantities
#ifndef SWIG

	//--------------------------------------------------------------------------
	// FORCE-LENGTH-VELOCITY PROPERTIES
	//--------------------------------------------------------------------------

	//--------------------------------------------------------------------------
	// COMPUTATIONS
	//--------------------------------------------------------------------------
	virtual double computeActuation(const SimTK::State& s) const;
	double calcTendonForce(const SimTK::State& s, double aNormTendonLength) const;
	double calcPassiveForce(const SimTK::State& s, double aNormFiberLength) const;
	double calcActiveForceFastFiber(const SimTK::State& s, double aNormFiberLength) const;
	double calcActiveForceSlowFiber(const SimTK::State& s, double aNormFiberLength) const;
	double calcFiberVelocityFastFiber(const SimTK::State& s, double aActivation, double aActiveForce, double aVelocityDependentForce) const;
	double calcFiberVelocitySlowFiber(const SimTK::State& s, double aActivation, double aActiveForce, double aVelocityDependentForce) const;
	virtual double computeIsometricForce(SimTK::State& s, double activation) const;

#endif
	virtual int getStateVariableYIndex(int index) const;

	OPENSIM_DECLARE_DERIVED(DiffMuscle, ActivationFiberLengthMuscle);

protected:
	// Model Component Interface
	virtual void setup(Model& aModel);
	virtual void createSystem(SimTK::MultibodySystem& system) const;
	virtual SimTK::Vector computeStateVariableDerivatives(const SimTK::State &s) const;

private:
	void setNull();
	void setupProperties();
//=============================================================================
};	// END of class DiffMuscle
//=============================================================================
} // end of namespace OpenSim
#endif // __DiffMuscle_h__